﻿using org.pdfclown.documents;
using org.pdfclown.documents.contents;
using org.pdfclown.documents.contents.fonts;
using org.pdfclown.documents.contents.objects;
using System;
using System.Collections.Specialized;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Text;

namespace HisQisGrabber
{
    class HisQisGrabber
    {
        private static NameValueCollection appSettings = System.Configuration.ConfigurationManager.AppSettings;

        private string Extract(string key, string delimiter, string text, out int end, int start = 0)
        {
            start = text.IndexOf(key, start);
            start += key.Length;
            end = text.IndexOf(delimiter, start + 1);
            return text.Substring(start, end - start);
        }

        private string InsertSessionId(string url, string sessionId)
        {
            return url.Replace("rds?", String.Format("{0}{1}?", appSettings["SessionSearch"], sessionId));
        }

        private bool Login(string url, string userId, string pwdId, out string sessionId)
        {
            WebRequest wr = WebRequest.Create(url);
            wr.Proxy.Credentials = CredentialCache.DefaultCredentials;
            wr.Method = "POST";
            string postData = String.Format("{0}={1}&{2}={3}", userId, appSettings["Username"], pwdId, appSettings["Password"]);
            byte[] byteArray = Encoding.UTF8.GetBytes(postData);
            wr.ContentType = "application/x-www-form-urlencoded";
            wr.ContentLength = byteArray.Length;

            using (Stream dataStream = wr.GetRequestStream())
            {
                dataStream.Write(byteArray, 0, byteArray.Length);
            }
            Console.Out.WriteLine("Logging in...");

            using (Stream s = wr.GetResponse().GetResponseStream())
            {
                using (StreamReader r = new StreamReader(s))
                {
                    string content = r.ReadToEnd();

                    // Login erfolgreich?
                    if (content.Contains(appSettings["LoginCheck"]))
                    {
                        Console.Out.WriteLine("Login successful.");
                        Console.WriteLine("Looking for session id...");
                        int end;
                        sessionId = Extract(appSettings["SessionSearch"], "?", content, out end);
                        Console.WriteLine("Session id found: {0}", sessionId);
                        return true;
                    }
                    else
                    {
                        Console.Out.WriteLine("Login failed!");
                        sessionId = null;
                        return false;
                    }
                }
            }
        }

        private string GetPdfUrl(string sessionId)
        {
            string url = InsertSessionId(appSettings["SelectionUrl"], sessionId);
            WebRequest wr = WebRequest.Create(url);
            wr.Proxy.Credentials = CredentialCache.DefaultCredentials;
            Console.WriteLine("Switching View...");
            string nextView;

            using (Stream s = wr.GetResponse().GetResponseStream())
            {
                Console.WriteLine("Switch complete.");

                using (StreamReader r = new StreamReader(s))
                {
                    string content = r.ReadToEnd();
                    Console.WriteLine("Looking for next view url...");
                    int start = content.IndexOf(appSettings["ViewSearch1"]);
                    start += appSettings["ViewSearch1"].Length;
                    int end;
                    nextView = Extract(appSettings["ViewSearch2"], "\"", content, out end, start + 1);
                    nextView = nextView.Replace("&amp;", "&");
                    nextView = InsertSessionId(nextView, sessionId);
                    Console.WriteLine("Next view url found: {0}", nextView);
                }
            }

            wr = WebRequest.Create(nextView);
            wr.Proxy.Credentials = CredentialCache.DefaultCredentials;
            Console.WriteLine("Switching View...");

            using (Stream s = wr.GetResponse().GetResponseStream())
            {
                Console.WriteLine("Switch complete.");

                using (StreamReader r = new StreamReader(s))
                {
                    string content = r.ReadToEnd();
                    Console.WriteLine("Looking for PDF url...");
                    int start = content.IndexOf(appSettings["PdfSearch1"]);
                    start = content.LastIndexOf(appSettings["PdfSearch2"], start);
                    start += appSettings["PdfSearch2"].Length;
                    int end = content.IndexOf('"', start + 1);
                    string pdfUrl = content.Substring(start, end - start);
                    pdfUrl = pdfUrl.Replace("&amp;", "&");
                    Console.WriteLine("PDF url found: {0}", pdfUrl);
                    return pdfUrl;
                }
            }
        }

        private bool SearchPdf(string filename)
        {
            string lookFor = appSettings["PdfLookFor"].ToLower();
            Console.WriteLine("Looking for \"{0}\" in the PDF...", lookFor);
            Document doc = new org.pdfclown.files.File(filename).Document;
            bool found = false;

            foreach (Page p in doc.Pages)
            {
                if (ExtractPdfText(new ContentScanner(p), lookFor))
                {
                    found = true;
                    break;
                }
            }

            Console.WriteLine("\"{0}\" was {1} in the pdf!", lookFor, found ? "FOUND" : "NOT found");
            return found;
        }

        private bool ExtractPdfText(ContentScanner s, string lookFor)
        {
            if (s == null)
                return false;

            while (s.MoveNext())
            {
                ContentObject content = s.Current;
                if (content is ShowText)
                {
                    Font font = s.State.Font;
                    // Extract the current text chunk, decoding it!
                    string text = font.Decode(((ShowText)content).Text);

                    if (text.ToLower().Contains(lookFor))
                        return true;
                }
                else if (content is Text || content is ContainerObject)
                {
                    // Scan the inner level!
                    if (ExtractPdfText(s.ChildLevel, lookFor))
                        return true;
                }
            }

            return false;
        }

        private void DownloadFile(string url)
        {
            WebRequest wr = WebRequest.Create(url);
            wr.Proxy.Credentials = CredentialCache.DefaultCredentials;
            Console.WriteLine("Downloading PDF...");

            using (Stream s = wr.GetResponse().GetResponseStream())
            {
                Console.WriteLine("Download complete.");
                Console.WriteLine("Writing file...");

                using (FileStream f = File.Open(appSettings["Filename"], FileMode.Create, FileAccess.Write))
                {
                    s.CopyTo(f);
                    Console.WriteLine("File saved to: {0}", f.Name);
                }

                bool found = SearchPdf(appSettings["Filename"]);
                bool openIfFound = Boolean.Parse(appSettings["OpenIfFound"]);
                bool openAlways = Boolean.Parse(appSettings["OpenAlways"]);

                if (found && openIfFound || openAlways)
                {
                    Console.WriteLine("Opening file...");
                    Process.Start(appSettings["Filename"]);
                }
            }
        }

        private string GetLoginUrl(out string userId, out string pwdId)
        {
            // Startseite aufrufen
            WebRequest wr = WebRequest.Create(appSettings["LoginUrl"]);
            wr.Proxy.Credentials = CredentialCache.DefaultCredentials;

            using (Stream s = wr.GetResponse().GetResponseStream())
            {
                Console.Out.WriteLine("Index file downloaded.");

                using (StreamReader r = new StreamReader(s))
                {
                    string content = r.ReadToEnd();
                    int end;

                    // Login Url extrahieren
                    Console.Out.WriteLine("Looking for login url...");
                    string loginUrl = Extract(appSettings["FormSearch"], "\"", content, out end);
                    loginUrl = loginUrl.Replace("&amp;", "&");
                    Console.Out.WriteLine("Login url found: {0}", loginUrl);

                    // POST ID für Username extrahieren
                    Console.Out.WriteLine("Looking for username id...");
                    userId = Extract(appSettings["UserSearch"], "\"", content, out end, end + 1);
                    Console.Out.WriteLine("Username id found: {0}", userId);

                    // POST ID für Passwort extrahieren
                    Console.Out.WriteLine("Looking for password id...");
                    pwdId = Extract(appSettings["PwdSearch"], "\"", content, out end, end + 1);
                    Console.Out.WriteLine("Password id found: {0}", pwdId);

                    return loginUrl;
                }
            }
        }

        public void Download()
        {
            string loginUrl, userId, pwdId;
            loginUrl = GetLoginUrl(out userId, out pwdId);

            // Einloggen
            string sessionId;
            bool loggedIn = Login(loginUrl, userId, pwdId, out sessionId);

            if (loggedIn)
            {
                // PDF Url extrahieren
                string pdfUrl = GetPdfUrl(sessionId);

                // Pdf herunterladen
                DownloadFile(pdfUrl);
            }
        }

    }
}
